#ifndef unigame_Quaternion_h
#define unigame_Quaternion_h

#include "Vector3.h"
#include "Matrix.h"
#include "math/Math.h"

namespace unigame
{
	class Quaternion
	{
	public:
		Quaternion(const Vector3f& v, float angle)
		{
			set(v, angle);
		}

		Quaternion(float x1, float y1, float z1, float w1):x(x1), y(y1), z(z1), w(w1){}

		Quaternion(float x, float y, float z)
		{
			setEulerByRad(x, y, z);
		}

		Quaternion(const Matrixf& m)
		{
			(*this) = m;
		}

		~Quaternion(){}
		Quaternion():x(0), y(0), z(0), w(1){}

		void fromTo(const Vector3f& from, const Vector3f& to);
		void set(const Vector3f& v, float angle);
		void setEulerByRad(const float x, const float y, const float z);

		void setEulerByAngle(const float x, const float y, const float z)
		{
			setEulerByRad(x * MULT_TO_RAD, y * MULT_TO_RAD, z * MULT_TO_RAD);
		}

		void setEulerByRad(const Vector3f& v)
		{
			setEulerByRad(v.x, v.y, v.z);
		}

		void setEulerByAngle(const Vector3f& v)
		{
			setEulerByAngle(v.x, v.y, v.z);
		}

		Quaternion& operator =(const Quaternion& q)
		{
			x = q.x;
			y = q.y;
			z = q.z;
			w = q.w;
			return *this;
		}

		Quaternion& operator =(const Matrixf& m);

		void toMatrix(Matrixf& m);

		void toEulerAngleByRad(Vector3f& v)
		{
			Matrixf m;
			this->toMatrix(m);
			m.getRotationByRad(v);
		}

		void toEulerAngleByAngle(Vector3f& v)
		{
			this->toEulerAngleByRad(v);
			v *= MULT_TO_ANGLE;
		}

		void normalize();

	private:
		void setToIdentity()
		{
			x = 0;
			y = 0;
			z = 0;
			w = 1;
		}

	public:
		float x;
		float y;
		float z;
		float w;
	};
}

#endif